package com.anntly.aspect;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.anntly.annotations.DBRouter;
import com.anntly.strategy.IDbRoute;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.Objects;

/**
 * @Author：Anntly
 * @Package：com.anntly.aspect
 * @Project：dbRouter
 * @name：DbRouteAspect
 * @Date：2024/7/3 8:24
 * @Filename：DbRouteAspect
 */
@Aspect
public class DbRouteAspect {

    @Resource
    private IDbRoute dbRoute;

    @Pointcut("@annotation(com.anntly.annotations.DBRouter)")
    public void routeAop() {

    }

    @Around("routeAop() && @annotation(dbRouter)")
    public Object doRoute(ProceedingJoinPoint proceedingJoinPoint, DBRouter dbRouter) throws Throwable {
        String routerKey = dbRouter.routerKey();
        Assert.notBlank(routerKey);
        Object[] args = proceedingJoinPoint.getArgs();
        if (args.length == 1) {
            if (args[0] instanceof String) {
                dbRoute.route((String) args[0]);
            } else {
                String keyValue = getFieldValue(args[0], routerKey);
                if (StrUtil.isNotBlank(keyValue)) {
                    dbRoute.route(keyValue);
                }
            }
        } else {
            for (Object arg : args) {
                String keyValue = getFieldValue(arg, routerKey);
                if (StrUtil.isNotBlank(keyValue)) {
                    dbRoute.route(keyValue);
                }
            }
        }
        Object result = proceedingJoinPoint.proceed();
        dbRoute.clear();
        return result;
    }

    private String getFieldValue(Object arg, String routerKey) throws NoSuchFieldException, IllegalAccessException {
        Field routeField = arg.getClass().getDeclaredField(routerKey);
        routeField.setAccessible(true);
        Object o = routeField.get(arg);
        routeField.setAccessible(false);
        if (Objects.isNull(o)) {
            return null;
        }
        return String.valueOf(o);
    }

}
